package com.heu.blood.examine.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heu.blood.application.dictenum.ApplicationStateEnum;
import com.heu.blood.application.dictenum.ApplicationVerifyStateEnum;
import com.heu.blood.application.entity.BloodApplicationEntity;
import com.heu.blood.application.service.BloodApplicationService;
import com.heu.blood.common.Constant.ConstantData;
import com.heu.blood.common.enums.BloodStateEnum;
import com.heu.blood.common.enums.OperateStateEnum;
import com.heu.blood.common.utils.GenerateNumberBySnowFlake;
import com.heu.blood.common.utils.PageUtils;
import com.heu.blood.common.utils.Query;
import com.heu.blood.dict.exception.DictExceptionEnum;
import com.heu.blood.examine.dao.OperateExamineDao;
import com.heu.blood.examine.dictenum.ExamineEnum;
import com.heu.blood.examine.dictenum.TradeTypeEnum;
import com.heu.blood.examine.entity.OperateExamineEntity;
import com.heu.blood.examine.service.OperateExamineService;
import com.heu.blood.examine.vo.OperateExamineSelectVo;
import com.heu.blood.globalExceptionHandler.MyException;
import com.heu.blood.match.entity.BloodInformationEntity;
import com.heu.blood.match.service.BloodInformationService;
import com.heu.blood.recycle.service.BloodReturnService;
import com.heu.blood.security.entity.UserEntity;
import com.heu.blood.security.exception.UserLoginException;
import com.heu.blood.storge.dao.BloodBackDao;
import com.heu.blood.storge.dictenum.BloodVerifyEnum;
import com.heu.blood.storge.dictenum.OutStorageReasonEnum;
import com.heu.blood.storge.entity.BloodBackEntity;
import com.heu.blood.storge.entity.BloodInStorgeEntity;
import com.heu.blood.storge.entity.BloodOutStorgeEntity;
import com.heu.blood.storge.entity.BloodVerifyStorgeEntity;
import com.heu.blood.storge.service.BloodBackService;
import com.heu.blood.storge.service.BloodInStorgeService;
import com.heu.blood.storge.service.BloodOutStorgeService;
import com.heu.blood.storge.service.BloodVerifyStorgeService;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service("operateExamineService")
public class OperateExamineServiceImpl extends ServiceImpl<OperateExamineDao, OperateExamineEntity> implements OperateExamineService {

    @Autowired
    BloodApplicationService bloodApplicationService;
    @Autowired
    BloodReturnService bloodReturnService;
    @Autowired
    BloodBackService bloodBackService;
    @Autowired
    BloodBackDao bloodBackDao;

    @Autowired
    BloodVerifyStorgeService bloodVerifyStorgeService;
    @Autowired
    BloodInformationService bloodInformationService;

    @Autowired
    BloodOutStorgeService bloodOutStorgeService;

    @Autowired
    BloodInStorgeService bloodInStorgeService;




    @Override
    public PageUtils queryPage(OperateExamineSelectVo selectVo) {
        // 在这里把分页做了
        Map<String,Object> params = new HashMap<>();
        params.put("limit",selectVo.getLimit());
        params.put("page",selectVo.getPage());

        // 按照当前登录的用户来进行筛选符合条件的审批信息
        LambdaQueryWrapper<OperateExamineEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Strings.isNotBlank(selectVo.getUserId()),OperateExamineEntity::getOperatorId,selectVo.getUserId());
        queryWrapper.orderByDesc(OperateExamineEntity::getGmtCreate); // 按照创建时间进行倒排
        // 筛选一下状态
        queryWrapper.eq(Strings.isNotBlank(selectVo.getOperateState()),OperateExamineEntity::getOperateState,
                selectVo.getOperateState());
        // 筛选一下交易类型
        queryWrapper.eq(Strings.isNotBlank(selectVo.getTradeType()),OperateExamineEntity::getTradeType,selectVo.getTradeType());
        // 按照开始时间和结束时间搞一下
        queryWrapper.ge(Strings.isNotBlank(selectVo.getStartTime()), OperateExamineEntity::getGmtCreate, selectVo.getStartTime())
                .le(Strings.isNotBlank(selectVo.getEndTime()), OperateExamineEntity::getGmtCreate, selectVo.getEndTime());
        IPage<OperateExamineEntity> page = this.page(
                new Query<OperateExamineEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    @Transactional
    // TODO 这里要记得更新传值了，导致Mybatis插件不生效
    public int sureExamine(OperateExamineEntity operateExamine) {

        // 1. 获取当前节点顺序和tradeId
        Integer curIndex = operateExamine.getExamineIndex();
        String tradeId = operateExamine.getTradeId();

        // 2. 如果不是第一个节点，查找上一级
        if (curIndex != null && curIndex > 1) {
            LambdaQueryWrapper<OperateExamineEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OperateExamineEntity::getTradeId, tradeId)
                    .eq(OperateExamineEntity::getExamineIndex, curIndex - 1);
            OperateExamineEntity preNode = this.getOne(wrapper);

            // 3. 校验上一级状态
            if (preNode == null || !OperateStateEnum.PASS.code().equals(preNode.getOperateState())) {
                throw new MyException(ExamineEnum.SUPERIOR_PENDING);
            }
        }

        operateExamine.setOperateState(OperateStateEnum.PASS.code());
        this.updateById(operateExamine);
        // 在这里根据审核的条目去判断逻辑
        // 1.如果审核的类型为申请单，则差找所有的审核项，看看是不是都是通过，如果都是通过，那么就把申请单的状态改成通过
        if(operateExamine.getTradeType().equals(TradeTypeEnum.BLOOD_APPLICATION.code())){
            LambdaQueryWrapper<OperateExamineEntity> applicationQueryWrapper = new LambdaQueryWrapper<>();
            applicationQueryWrapper.eq(Strings.isNotBlank(operateExamine.getTradeId()),OperateExamineEntity::getTradeId,operateExamine.getTradeId());
            List<OperateExamineEntity> operateExamineEntityList = this.list(applicationQueryWrapper);
            // 判断是不是所有的都是通过
            boolean flag = true;
            for(OperateExamineEntity cur : operateExamineEntityList){
                // 为空未审核或者是有拒绝的意见
                if(Strings.isBlank(cur.getOperateState())  || cur.getOperateState().equals(OperateStateEnum.WAIT.code()) || cur.getOperateState().equals(OperateStateEnum.REJECT.code())){
                    flag = false;
                    break;
                }
            }
            // 如果全都是通过 把申请单的状态修改为通过
            if(flag){
                LambdaUpdateWrapper<BloodApplicationEntity> bloodApplicationEntityUpdateWrapper = new LambdaUpdateWrapper<>();
                bloodApplicationEntityUpdateWrapper.set(BloodApplicationEntity::getVerifyState, ApplicationVerifyStateEnum.PASS.code());
                bloodApplicationEntityUpdateWrapper.set(BloodApplicationEntity::getApplicationState,ApplicationStateEnum.BLOOD_ANALYSIS.code());
                bloodApplicationEntityUpdateWrapper.eq(Strings.isNotBlank(operateExamine.getTradeId()),BloodApplicationEntity::getApplicationId,operateExamine.getTradeId());
                bloodApplicationService.update(bloodApplicationEntityUpdateWrapper);
            }
        } else if (operateExamine.getTradeType().equals(TradeTypeEnum.BLOOD_BACK.code())) {
            String bloodId = operateExamine.getTradeId();
            LambdaUpdateWrapper<BloodBackEntity> bloodBackUpdate = new LambdaUpdateWrapper<>();

            String dateStr = new java.text.SimpleDateFormat("yyyyMMdd").format(new Date());
            String backPrefix = ConstantData.BLOOD_BACK_NO_WORK_ID;

            QueryWrapper<BloodBackEntity> backWrapper = new QueryWrapper<>();
            backWrapper.likeRight("blood_return_id", backPrefix + dateStr);  // 只查当天数据
            backWrapper.orderByDesc("blood_return_id");
            backWrapper.last("limit 1");
            BloodBackEntity maxBackEntity =bloodBackDao.selectOne(backWrapper);

            int nextSeq = 1;
            if (maxBackEntity != null && maxBackEntity.getBloodId() != null) {
            String maxNo = maxBackEntity.getBloodId();
            // 前缀 + 日期 + 4位序列
            if (maxNo.length() >= (backPrefix.length() + 12)) {
                String seqStr = maxNo.substring(backPrefix.length() + 8, backPrefix.length() + 12);
                nextSeq = Integer.parseInt(seqStr) + 1;
             }
             }
            String seqStr = String.format("%04d", nextSeq);
            String bloodReturnId = backPrefix + dateStr + seqStr;

            bloodBackUpdate.eq(BloodBackEntity::getBloodId,bloodId)
                    .set(BloodBackEntity::getGmtCreate,new Date())
                    .set(BloodBackEntity::getGmtModified,new Date())
                    .set(BloodBackEntity::getBloodReturnId,bloodReturnId);
            bloodBackDao.update(null, bloodBackUpdate);

            LambdaUpdateWrapper<BloodVerifyStorgeEntity> verifyUpdateWrapper = new LambdaUpdateWrapper<>();
            verifyUpdateWrapper.set(BloodVerifyStorgeEntity::getVerifyResult, BloodVerifyEnum.VERIFY_FAIL.code());
            verifyUpdateWrapper.eq(BloodVerifyStorgeEntity::getBloodId,bloodId);
            bloodVerifyStorgeService.update(verifyUpdateWrapper);

            LambdaUpdateWrapper<BloodInformationEntity> informationUpdateWrapper = new LambdaUpdateWrapper<>();
            informationUpdateWrapper.set(BloodInformationEntity::getBloodState, BloodStateEnum.RETURN_TO_BLOODSTATION.code());
            informationUpdateWrapper.eq(BloodInformationEntity::getBloodId,bloodId);
            bloodInformationService.update(informationUpdateWrapper);

            LambdaUpdateWrapper<BloodInStorgeEntity> storageUpdateWrapper = new LambdaUpdateWrapper<>();
            storageUpdateWrapper.set(BloodInStorgeEntity::getBloodState, BloodStateEnum.RETURN_TO_BLOODSTATION.code());
            storageUpdateWrapper.eq(BloodInStorgeEntity::getBloodId,bloodId);
            bloodInStorgeService.update(storageUpdateWrapper);

            LambdaQueryWrapper<BloodInformationEntity> bloodInformationQueryWrapper =new LambdaQueryWrapper<>();
            bloodInformationQueryWrapper.eq(BloodInformationEntity::getBloodId,bloodId);
            BloodInformationEntity bloodInformationEntity = bloodInformationService.getOne(bloodInformationQueryWrapper);

            //7.同步更新到出库表中
            BloodOutStorgeEntity outStorgeEntity = new BloodOutStorgeEntity();
            BeanUtils.copyProperties(bloodInformationEntity,outStorgeEntity);
//            GenerateNumberBySnowFlake generateNumberBySnowFlake = new GenerateNumberBySnowFlake(ConstantData.BLOOD_OUT_STORAGE_NO_WORK_ID, ConstantData.BLOOD_OUT_STORAGE_NO_PREFIX);
//            String outStorageId = generateNumberBySnowFlake.genNumberByflag();

            String outPrefix = ConstantData.BLOOD_OUT_STORAGE_NO_PREFIX;
            String outDateStr = new SimpleDateFormat("yyyyMMdd").format(new Date());
            QueryWrapper<BloodOutStorgeEntity> wrapper = new QueryWrapper<>();
            wrapper.likeRight("blood_bank_delivery_id", outPrefix + outDateStr);
            wrapper.orderByDesc("blood_bank_delivery_id");
            wrapper.last("limit 1");
            BloodOutStorgeEntity maxEntity = bloodOutStorgeService.getOne(wrapper);
            int outNextSeq = 1;
            if (maxEntity != null && maxEntity.getBloodBankDeliveryId() != null) {
                String maxNo = maxEntity.getBloodBankDeliveryId();
                if (maxNo.length() >= 12) {
                    String outSeqStr = maxNo.substring(10, 14);
                    outNextSeq = Integer.parseInt(outSeqStr) + 1;
                }
            }
            String outSeqStr = String.format("%04d", outNextSeq);
            String outStorageId = outPrefix + outDateStr +outSeqStr;

            outStorgeEntity.setOutStorgeTime(new Date());
            outStorgeEntity.setBloodBankDeliveryId(outStorageId);
            outStorgeEntity.setOutStorgeReason(OutStorageReasonEnum.BLOOD_BACK.code());
            bloodOutStorgeService.save(outStorgeEntity);

            operateExamine.setOperateState(OperateStateEnum.PASS.code());
            this.updateById(operateExamine);
        }

        return 0;
    }

    @Override
    public int rejectExamine(OperateExamineEntity operateExamine) {
        operateExamine.setOperateState(OperateStateEnum.REJECT.code());
        this.updateById(operateExamine);

        // 新增：同步更新申请单状态为REJECT
        if(operateExamine.getTradeType().equals(TradeTypeEnum.BLOOD_APPLICATION.code())){
            LambdaUpdateWrapper<BloodApplicationEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(BloodApplicationEntity::getVerifyState, OperateStateEnum.REJECT.code());
            updateWrapper.eq(BloodApplicationEntity::getApplicationId, operateExamine.getTradeId());
            bloodApplicationService.update(updateWrapper);
        }
        return 0;
    }

    @Override
    public int addOne(OperateExamineEntity operateExamine) {
        // 首先将其记录为待处理的状态
        operateExamine.setOperateState(OperateStateEnum.WAIT.code());
        this.save(operateExamine);
        return 0;
    }

    @Override
    public Object info(OperateExamineEntity operateExamineEntity) {
        Object res = null;
        // 获取交易的id
        String tradeId = operateExamineEntity.getTradeId();

        // 获取交易类型
        String tradeType = operateExamineEntity.getTradeType();
        if(tradeType.equals(TradeTypeEnum.BLOOD_APPLICATION.code())){
            // 获取对应申请单的详细内容
            res = bloodApplicationService.applicationInfo(tradeId);
        }else if(tradeType.equals(TradeTypeEnum.BLOOD_RETURN.code())){
            // 获取对应退血的详细内容
            res = bloodReturnService.selectByReturnId(tradeId);
        }else if (tradeType.equals(TradeTypeEnum.BLOOD_BACK.code())){
            res = bloodBackService.selectByBloodId(tradeId);
        }
        return res;
    }

    @Override
    public int deleteExamine(OperateExamineEntity operateExamineEntity) {
        boolean b = this.removeById(operateExamineEntity.getId());
        return b ? 1 : 0;
    }

}
